home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / c / indents.zip / lexi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-30  |  21.0 KB  |  597 lines

  1. /**
  2.  * Copyright (c) 1985 Sun Microsystems, Inc.
  3.  * Copyright (c) 1980 The Regents of the University of California.
  4.  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms are permitted provided
  8.  * that the above copyright notice and this paragraph are duplicated in all
  9.  * such forms and that any documentation, advertising materials, and other
  10.  * materials related to such distribution and use acknowledge that the
  11.  * software was developed by the University of California, Berkeley, the
  12.  * University of Illinois, Urbana, and Sun Microsystems, Inc.  The name of
  13.  * either University or Sun Microsystems may not be used to endorse or
  14.  * promote products derived from this software without specific prior written
  15.  * permission. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
  16.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
  17.  * OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  */
  19.  
  20. #include "globals.h"
  21. #include "codes.h"
  22.  
  23. #ifndef lint
  24. # ifndef ANSIC
  25. static char     sccsid[] = "@(#)lexi.c    6.0 (Berkeley) 92/06/15";
  26. # endif         /* ANSIC */
  27. #endif          /* not lint */
  28.  
  29. /* Here we have the token scanner for indent.  It scans off one token and
  30.  * puts it in the global variable "token".  It returns a code, indicating the
  31.  * type of token scanned. */
  32.  
  33. #include <ctype.h>
  34. #include <string.h>
  35.  
  36. typedef enum char_type {
  37.     alphanum = 1,
  38.     opchar = 3,
  39.     colonchar = 4
  40. } char_type;
  41.  
  42. struct templ {
  43.     char           *rwd;
  44.     int             rwcode;
  45.     cplus_flag      cplus;
  46. };
  47.  
  48. struct templ    specials[100] =
  49. {
  50.     {"switch", 1, c_and_cplus},
  51.     {"case", 2, c_and_cplus},
  52.     {"break", 0, c_and_cplus},
  53.     {"struct", 3, c_and_cplus},
  54.     {"union", 3, c_and_cplus},
  55.     {"enum", 3, c_and_cplus},
  56.     {"default", 2, c_and_cplus},
  57.     {"int", 4, c_and_cplus},
  58.     {"char", 4, c_and_cplus},
  59.     {"float", 4, c_and_cplus},
  60.     {"double", 4, c_and_cplus},
  61.     {"long", 4, c_and_cplus},
  62.     {"short", 4, c_and_cplus},
  63.     {"typedef", 8, c_and_cplus},
  64.     {"unsigned", 4, c_and_cplus},
  65.     {"register", 4, c_and_cplus},
  66.     {"static", 4, c_and_cplus},
  67.     {"global", 4, c_and_cplus},
  68.     {"extern", 4, c_and_cplus},
  69.     {"void", 4, c_and_cplus},
  70.     {"goto", 0, c_and_cplus},
  71.     {"return", 0, c_and_cplus},
  72.     {"if", 5, c_and_cplus},
  73.     {"while", 5, c_and_cplus},
  74.     {"for", 5, c_and_cplus},
  75.     {"else", 6, c_and_cplus},
  76.     {"do", 6, c_and_cplus},
  77.     {"sizeof", 7, c_and_cplus},
  78.     {"class", 3, cplus_only},
  79.     {"public", 2, cplus_only},
  80.     {"private", 2, cplus_only},
  81.     {"protected", 2, cplus_only},
  82.     {"volatile", 4, c_and_cplus},
  83.     {0, 0}
  84. };
  85.  
  86. char            chartype[128] =
  87. {                               /* this is used to facilitate the decision of
  88.                                  * what type (alphanumeric, operator) each
  89.                                  * character is */
  90.     0, 0, 0, 0, 0, 0, 0, 0,
  91.     0, 0, 0, 0, 0, 0, 0, 0,
  92.     0, 0, 0, 0, 0, 0, 0, 0,
  93.     0, 0, 0, 0, 0, 0, 0, 0,
  94.     0, 3, 0, 0, 1, 3, 3, 0,
  95.     0, 0, 3, 3, 0, 3, 0, 3,
  96.     1, 1, 1, 1, 1, 1, 1, 1,
  97.     1, 1, 4, 0, 3, 3, 3, 3,
  98.     0, 1, 1, 1, 1, 1, 1, 1,
  99.     1, 1, 1, 1, 1, 1, 1, 1,
  100.     1, 1, 1, 1, 1, 1, 1, 1,
  101.     1, 1, 1, 0, 0, 0, 3, 1,
  102.     0, 1, 1, 1, 1, 1, 1, 1,
  103.     1, 1, 1, 1, 1, 1, 1, 1,
  104.     1, 1, 1, 1, 1, 1, 1, 1,
  105.     1, 1, 1, 0, 3, 0, 3, 0
  106. };
  107.  
  108.  
  109.  
  110. #ifdef ANSIC
  111. int             lexi(void)
  112. #else           /* ANSIC */
  113. int             lexi()
  114. #endif          /* ANSIC */
  115. {
  116.     register char  *tok = NULL; /* local pointer to next char in token */
  117.     int             unary_delim;/* this is set to 1 if the current token
  118.                                  * 
  119.                                  * forces a following operator to be unary */
  120.     static int      last_code = 0;  /* the last token type returned */
  121.     static int      l_struct = 0;   /* set to 1 if the last token was
  122.                                      * 'struct' */
  123.     static int      l_struct_start = 0; /* set at struct, cleared at { or ; */
  124.     static int      l_class = 0;/* in c++, class name coming next. */
  125.     int             code;       /* internal code to be returned */
  126.     char            qchar;      /* the delimiter character for a string */
  127.  
  128.     tok = token;                /* point to start of place to save token */
  129.     unary_delim = false;
  130.     ps.col_1 = ps.last_nl;      /* tell world that this token started in
  131.                                  * column 1 iff the last thing scanned was a
  132.                                  * newline */
  133.     ps.last_nl = false;
  134.  
  135.     while (*buf_ptr == ' ' || *buf_ptr == '\t') {   /* get rid of blanks */
  136.         ps.col_1 = false;       /* leading blanks imply token is not in
  137.                                  * column 1 */
  138.         if (++buf_ptr >= buf_end)
  139.             fill_buffer();
  140.     }
  141.  
  142.     /* Scan an alphanumeric token */
  143.     /* In c++, :: starting token is OK, as is ~ sometimes */
  144.     /* well, int x = ~y; will work oddly here */
  145.     if (((char_type) chartype[*buf_ptr] == alphanum || buf_ptr[0] == '.' && isdigit(buf_ptr[1])) ||
  146.         (cplus && buf_ptr[0] == ':' && buf_ptr[1] == ':') ||
  147.         (cplus && ps.in_decl && *buf_ptr == '~'
  148.          && (char_type) chartype[buf_ptr[1]] == alphanum)   /* destructors in
  149.                                                              * classdefs */
  150.         ) {
  151.         /* we have a character or number */
  152.         register char  *j = NULL;   /* used for searching through list of
  153.                                      * reserved words */
  154.         register struct templ *p;
  155.  
  156.         if (isdigit(*buf_ptr) || buf_ptr[0] == '.' && isdigit(buf_ptr[1])) {
  157.             int             seendot = 0,
  158.                             seenexp = 0;
  159.  
  160.             if (*buf_ptr == '0' &&
  161.                 (buf_ptr[1] == 'x' || buf_ptr[1] == 'X')) {
  162.                 *tok++ = *buf_ptr++;
  163.                 *tok++ = *buf_ptr++;
  164.                 while (isxdigit(*buf_ptr))
  165.                     *tok++ = *buf_ptr++;
  166.             } else
  167.                 while (1) {
  168.                     if (*buf_ptr == '.')
  169.                         if (seendot)
  170.                             break;
  171.                         else
  172.                             seendot++;
  173.                     *tok++ = *buf_ptr++;
  174.                     if (!isdigit(*buf_ptr) && *buf_ptr != '.')
  175.                         if ((*buf_ptr != 'E' && *buf_ptr != 'e') || seenexp)
  176.                             break;
  177.                         else {
  178.                             seenexp++;
  179.                             seendot++;
  180.                             *tok++ = *buf_ptr++;
  181.                             if (*buf_ptr == '+' || *buf_ptr == '-')
  182.                                 *tok++ = *buf_ptr++;
  183.                         }
  184.                 }
  185.             if (*buf_ptr == 'L' || *buf_ptr == 'l')
  186.                 *tok++ = *buf_ptr++;
  187.         } else {
  188.             int             first;
  189.  
  190.             first = 1;
  191.             while ((char_type) chartype[*buf_ptr] == alphanum ||
  192.                    (buf_ptr[0] == ':' && buf_ptr[1] == ':' && cplus) ||
  193.                    (cplus && first && buf_ptr[0] == '~')) { /* copy it over */
  194.                 int             colonp;
  195.  
  196.                 first = 0;
  197.                 colonp = *buf_ptr == ':';
  198.                 *tok++ = *buf_ptr++;
  199.                 if (colonp) {
  200.                     *tok++ = *buf_ptr++;
  201.                     /* foo::~foo */
  202.                     if (*buf_ptr == '~')
  203.                         *tok++ = *buf_ptr++;
  204.                     colonp = 0;
  205.                 }
  206.                 if (buf_ptr >= buf_end)
  207.                     fill_buffer();
  208.             }
  209.         }
  210.         *tok++ = '\0';
  211.         while (*buf_ptr == ' ' || *buf_ptr == '\t') {   /* get rid of blanks */
  212.             if (++buf_ptr >= buf_end)
  213.                 fill_buffer();
  214.         }
  215.         ps.its_a_keyword = false;
  216.         ps.sizeof_keyword = false;
  217.         if (l_struct) {         /* if last token was 'struct', then this
  218.                                  * token should be treated as a declaration */
  219.             if (l_class)
  220.                 addkey(tok, 4);
  221.             l_class = false;
  222.             l_struct = false;
  223.             last_code = ident;
  224.             ps.last_u_d = true;
  225.             return (decl);
  226.         }
  227.         ps.last_u_d = false;    /* Operator after identifier is binary */
  228.         last_code = ident;      /* Remember that this is the code we will
  229.                                  * return */
  230.  
  231.         /* This loop will check if the token is a keyword. */
  232.         for (p = specials; (j = p->rwd) != 0; p++) {
  233.             tok = token;        /* point at scanned token */
  234.             if (*j++ != *tok++ || *j++ != *tok++)
  235.                 continue;       /* This test depends on the fact that
  236.                                  * identifiers are always at least 1
  237.                                  * character long (i.e. the first two bytes
  238.                                  * of the identifier are always meaningful) */
  239.             if (tok[-1] == 0)
  240.                 break;          /* If its a one-character identifier */
  241.             while (*tok++ == *j)
  242.                 if (*j++ == 0 &&
  243.                     (p->cplus == c_and_cplus ||
  244.                      (cplus && p->cplus == cplus_only) ||
  245.                      (!cplus && p->cplus == c_only)))
  246.                     goto found_keyword; /* I wish that C had a multi-level
  247.                                          * break... */
  248.         }
  249.         if (p->rwd) {           /* we have a keyword */
  250.     found_keyword:
  251.             ps.its_a_keyword = true;
  252.             ps.last_u_d = true;
  253.             switch (p->rwcode) {
  254.             case 1:             /* it is a switch */
  255.                 return (swstmt);
  256.             case 2:             /* a case or default */
  257.                 return (casestmt);
  258.             case 3:             /* a "struct" */
  259.                 if (ps.p_l_follow)
  260.                     break;      /* inside parens: cast */
  261.                 l_struct = true;
  262.                 if (cplus)
  263.                     l_struct_start = true;
  264.                 /* automatically note keywords */
  265.                 if (cplus && strcmp(tok, "class") == 0 ||
  266.                     strcmp(tok, "struct") == 0 ||
  267.                     strcmp(tok, "union") == 0 ||
  268.                     strcmp(tok, "enum") == 0)
  269.                     l_class = true;
  270.                 /* Next time around, we will want to know that we have had a
  271.                  * 'struct' */
  272.             case 4:             /* one of the declaration keywords */
  273.                 if (ps.p_l_follow) {
  274.                     ps.cast_mask |= 1 << ps.p_l_follow;
  275.                     break;      /* inside parens: cast */
  276.                 }
  277.                 last_code = decl;
  278.                 return (decl);
  279.             case 5:             /* if, while, for */
  280.                 return (sp_paren);
  281.             case 6:             /* do, else */
  282.                 return (sp_nparen);
  283.             case 7:
  284.                 ps.sizeof_keyword = true;
  285.                 return (ident);
  286.             case 8:             /* typedef is a decl */
  287.                 last_code = decl;
  288.                 return (decl);
  289.             default:            /* all others are treated like any other
  290.                                  * identifier */
  291.                 return (ident);
  292.             }                   /* end of switch */
  293.         }                       /* end of if (found_it) */
  294.         if (*buf_ptr == '(' && ps.tos <= 1 && ps.ind_level == 0) {
  295.             register char  *tp = buf_ptr;
  296.  
  297.             while (tp < buf_end)
  298.                 if (*tp++ == ')' && *tp == ';')
  299.                     goto not_proc;
  300.             strncpy(ps.procname, token, sizeof ps.procname - 1);
  301.             ps.in_parameter_declaration = 1;
  302.     not_proc:;
  303.         }
  304.         /* The following hack attempts to guess whether or not the current
  305.          * token is in fact a declaration keyword -- one that has been
  306.          * typedefd */
  307.         if (((*buf_ptr == '*' && buf_ptr[1] != '=') || isalpha(*buf_ptr) || *buf_ptr == '_')
  308.             && !ps.p_l_follow
  309.             && !ps.block_init
  310.             && (ps.last_token == rparen || ps.last_token == semicolon ||
  311.                 ps.last_token == decl ||
  312.                 ps.last_token == lbrace || ps.last_token == rbrace)) {
  313.             ps.its_a_keyword = true;
  314.             ps.last_u_d = true;
  315.             last_code = decl;
  316.             return decl;
  317.         }
  318.         if (last_code == decl)  /* if this is a declared variable, then
  319.                                  * following sign is unary */
  320.             ps.last_u_d = true; /* will make "int a -1" work */
  321.         last_code = ident;
  322.         return (ident);         /* the ident is not in the list */
  323.     }                           /* end of processing for alpanum character */
  324.     /* l l l Scan a non-alphanumeric token */
  325.     l_class = false;            /* struct { are not defining a class. */
  326.     *tok++ = *buf_ptr;          /* if it is only a one-character token, it is
  327.                                  * moved here */
  328.     *tok = '\0';
  329.     if (++buf_ptr >= buf_end)
  330.         fill_buffer();
  331.  
  332.     switch (*token) {
  333.     case '\n':
  334.         unary_delim = ps.last_u_d;
  335.         ps.last_nl = true;      /* remember that we just had a newline */
  336.         code = (had_eof ? 0 : newline);
  337.  
  338.         /* if data has been exhausted, the newline is a dummy, and we should
  339.          * return code to stop */
  340.         break;
  341.  
  342.     case '\'':                  /* start of quoted character */
  343.     case '"':                   /* start of string */
  344.         qchar = *token;
  345.         if (troff) {
  346.             tok[-1] = '`';
  347.             if (qchar == '"')
  348.                 *tok++ = '`';
  349.             tok = chfont(&bodyf, &stringf, tok);
  350.         }
  351.         do {                    /* copy the string */
  352.             while (1) {         /* move one character or [/<char>]<char> */
  353.                 if (*buf_ptr == '\n') {
  354.                     fprintf(stderr, "%d: Unterminated literal\n", line_no);
  355.                     goto stop_lit;
  356.                 }
  357.                 *tok = *buf_ptr++;
  358.                 if (buf_ptr >= buf_end)
  359.                     fill_buffer();
  360.  
  361.                 if (had_eof || ((tok - token) > (bufsize - 2))) {
  362.                     printf("Unterminated literal\n");
  363.                     ++tok;
  364.                     goto stop_lit;
  365.                     /* get outof literal copying loop */
  366.                 }
  367.                 if (*tok == BACKSLASH) {    /* if escape, copy extra char */
  368.                     if (*buf_ptr == '\n')   /* check for escaped newline */
  369.                         ++line_no;
  370.                     if (troff) {
  371.                         *++tok = BACKSLASH;
  372.                         if (*buf_ptr == BACKSLASH)
  373.                             *++tok = BACKSLASH;
  374.                     }
  375.                     *++tok = *buf_ptr++;
  376.                     ++tok;      /* we must increment this again because we
  377.                                  * copied two chars */
  378.                     if (buf_ptr >= buf_end)
  379.                         fill_buffer();
  380.                 } else
  381.                     break;      /* we copied one character */
  382.             }                   /* end of while (1) */
  383.         } while (*tok++ != qchar);
  384.         if (troff) {
  385.             tok = chfont(&stringf, &bodyf, tok - 1);
  386.             if (qchar == '"')
  387.                 *tok++ = '\'';
  388.         }
  389. stop_lit:
  390.         code = ident;
  391.         break;
  392.  
  393.     case ('('):
  394.     case ('['):
  395.         unary_delim = true;
  396.         code = lparen;
  397.         break;
  398.  
  399.     case (')'):
  400.     case (']'):
  401.         code = rparen;
  402.         break;
  403.  
  404.     case '#':
  405.         unary_delim = ps.last_u_d;
  406.         code = preesc;
  407.         break;
  408.  
  409.     case '?':
  410.         unary_delim = true;
  411.         code = question;
  412.         break;
  413.  
  414.     case (':'):
  415.         if (l_struct_start)
  416.             code = ident;
  417.         else
  418.             code = colon;
  419.         unary_delim = true;
  420.         break;
  421.  
  422.     case (';'):
  423.         l_struct_start = false;
  424.         unary_delim = true;
  425.         code = semicolon;
  426.         break;
  427.  
  428.     case ('{'):
  429.         l_struct_start = false;
  430.         unary_delim = true;
  431.  
  432.         /* if (ps.in_or_st) ps.block_init = 1; */
  433.         /* ?    code = ps.block_init ? lparen : lbrace; */
  434.         code = lbrace;
  435.         break;
  436.  
  437.     case ('}'):
  438.         unary_delim = true;
  439.         /* ?    code = ps.block_init ? rparen : rbrace; */
  440.         code = rbrace;
  441.         break;
  442.  
  443.     case 014:                   /* a form feed */
  444.         unary_delim = ps.last_u_d;
  445.         ps.last_nl = true;      /* remember this so we can set 'ps.col_1'
  446.                                  * right */
  447.         code = form_feed;
  448.         break;
  449.  
  450.     case (','):
  451.         unary_delim = true;
  452.         code = comma;
  453.         break;
  454.  
  455.     case '.':
  456.         unary_delim = false;
  457.         code = period;
  458.         break;
  459.  
  460.     case '-':
  461.     case '+':                   /* check for -, +, --, ++ */
  462.         code = (ps.last_u_d ? unary_op : binary_op);
  463.         unary_delim = true;
  464.  
  465.         if (*buf_ptr == token[0]) {
  466.             /* check for doubled character */
  467.             *tok++ = *buf_ptr++;
  468.             /* buffer overflow will be checked at end of loop */
  469.             if (last_code == ident || last_code == rparen) {
  470.                 code = (ps.last_u_d ? unary_op : postop);
  471.                 /* check for following ++ or -- */
  472.                 unary_delim = false;
  473.             }
  474.         } else if (*buf_ptr == '=')
  475.             /* check for operator += */
  476.             *tok++ = *buf_ptr++;
  477.         else if (*buf_ptr == '>') {
  478.             /* check for operator -> */
  479.             *tok++ = *buf_ptr++;
  480.             if (!pointer_as_binop) {
  481.                 unary_delim = false;
  482.                 code = unary_op;
  483.                 ps.want_blank = false;
  484.             }
  485.         }
  486.         break;                  /* buffer overflow will be checked at end of
  487.                                  * switch */
  488.  
  489.     case '=':
  490.         if (ps.in_or_st)
  491.             ps.block_init = 1;
  492. #if 0
  493.         if (chartype[*buf_ptr] == opchar) { /* we have two char assignment */
  494.             tok[-1] = *buf_ptr++;
  495.             if ((tok[-1] == '<' || tok[-1] == '>') && tok[-1] == *buf_ptr)
  496.                 *tok++ = *buf_ptr++;
  497.             *tok++ = '=';       /* Flip =+ to += */
  498.             *tok = 0;
  499.         }
  500. #else           /* 0 */
  501.         if (*buf_ptr == '=') {  /* == */
  502.             *tok++ = '=';       /* Flip =+ to += */
  503.             buf_ptr++;
  504.             *tok = 0;
  505.         }
  506. #endif          /* 0 */
  507.         code = binary_op;
  508.         unary_delim = true;
  509.         break;
  510.         /* can drop through!!! */
  511.  
  512.     case '>':
  513.     case '<':
  514.     case '!':                   /* ops like <, <<, <=, !=, etc. */
  515.         if (*buf_ptr == '>' || *buf_ptr == '<' || *buf_ptr == '=') {
  516.             *tok++ = *buf_ptr;
  517.             if (++buf_ptr >= buf_end)
  518.                 fill_buffer();
  519.         }
  520.         if (*buf_ptr == '=')
  521.             *tok++ = *buf_ptr++;
  522.         code = (ps.last_u_d ? unary_op : binary_op);
  523.         unary_delim = true;
  524.         break;
  525.  
  526.     default:
  527.         if (token[0] == '/' && *buf_ptr == '*') {
  528.             /* it is start of a C comment */
  529.             *tok++ = '*';
  530.  
  531.             if (++buf_ptr >= buf_end)
  532.                 fill_buffer();
  533.  
  534.             code = comment;
  535.             unary_delim = ps.last_u_d;
  536.             break;
  537.         }
  538.         if (token[0] == '/' && *buf_ptr == '/') {
  539.             /* it is start of a C++ comment */
  540.             *tok++ = '/';
  541.  
  542.             if (++buf_ptr >= buf_end)
  543.                 fill_buffer();
  544.  
  545.             code = cc_commnt;
  546.             ps.cc_comment++;
  547.             unary_delim = ps.last_u_d;
  548.             break;
  549.         }
  550.         while (*(tok - 1) == *buf_ptr || *buf_ptr == '=') {
  551.             /* handle ||, &&, etc, and also things as in int *****i */
  552.             *tok++ = *buf_ptr;
  553.             if (++buf_ptr >= buf_end)
  554.                 fill_buffer();
  555.         }
  556.         code = (ps.last_u_d ? unary_op : binary_op);
  557.         unary_delim = true;
  558.  
  559.  
  560.     }                           /* end of switch */
  561.     if (code != newline) {
  562.         l_struct = false;
  563.         last_code = code;
  564.     }
  565.     if (buf_ptr >= buf_end)     /* check for input buffer empty */
  566.         fill_buffer();
  567.     ps.last_u_d = unary_delim;
  568.     *tok = '\0';                /* null terminate the token */
  569.     return (code);
  570. };
  571.  
  572. /* Add the given keyword to the keyword table, using val as the keyword type */
  573. #ifdef ANSIC
  574. void            addkey(char *key, int val)
  575. #else           /* ANSIC */
  576. addkey(key, val)
  577.     char           *key;
  578.     int             val;
  579. #endif          /* ANSIC */
  580. {
  581.     register struct templ *p = specials;
  582.  
  583.     while (p->rwd)
  584.         if (p->rwd[0] == key[0] && strcmp(p->rwd, key) == 0)
  585.             return;
  586.         else
  587.             p++;
  588.     if (p >= specials + sizeof specials / sizeof specials[0])
  589.         return;                 /* For now, table overflows are silently
  590.                                  * ignored */
  591.     p->rwd = key;
  592.     p->rwcode = val;
  593.     p[1].rwd = 0;
  594.     p[1].rwcode = 0;
  595.     return;
  596. }
  597.